package liurong.driver.reference;

import java.io.IOException;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 
 * @desc 虚拟机参数：-Xms3M -Xmx3M -Xmn1M -XX:+PrintGCDetails -XX:+PrintGCDateStamps
 *
 * @author liurong
 *
 * @date 2020年3月17日
 */
public class ReferenceTest {

	private static final ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();

	private static final List<SoftReference<ReferenceTest>> SOFT_REFERENCES = new ArrayList<SoftReference<ReferenceTest>>();
	private static final List<WeakReference<ReferenceTest>> WEAK_REFERENCES = new ArrayList<WeakReference<ReferenceTest>>();

	public static void main(String[] args) {
		try {
			ReferenceTest referenceTest = new ReferenceTest();
			referenceTest.start();
			System.in.read();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void start() {
		// 启动gc监控线程
		gcNotify();

		// 启动监控统计线程
		monitor();

		// 创建实例并hold
		for (int i = 0; i < 10000; i++) {
			try {
				this.instanceObject();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		while (true) {
			try {
				TimeUnit.SECONDS.sleep(2);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println("gc");
			System.gc();
		}
	}

	/**
	 * 创建实例对象，并且hold
	 */
	private void instanceObject() {
		WeakReference<ReferenceTest> weakReference = new WeakReference<ReferenceTest>(new ReferenceTest(), refQueue);
		SoftReference<ReferenceTest> softReference = new SoftReference<ReferenceTest>(new ReferenceTest(), refQueue);
		WEAK_REFERENCES.add(weakReference);
		SOFT_REFERENCES.add(softReference);
	}

	/**
	 * 统计个数
	 */
	private void monitor() {
		new Thread(new Runnable() {

			@Override
			public void run() {
				while (true) {
					System.out.println("weak引用个数：" + WEAK_REFERENCES.size());
					System.out.println("soft引用个数：" + SOFT_REFERENCES.size());
					try {
						TimeUnit.SECONDS.sleep(2);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}).start();
	}

	/**
	 * GC释放引用对象之后通知线程
	 */
	private void gcNotify() {
		new Thread(new Runnable() {
			@Override
			public void run() {
				while (true) {
					try {
						Reference<? extends Object> poll = refQueue.poll();
						if (poll != null) {
							if (poll instanceof WeakReference) {
								WEAK_REFERENCES.remove(poll);
							} else if (poll instanceof SoftReference) {
								SOFT_REFERENCES.remove(poll);
							}
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}).start();
	}

}
